import Point2D from "../Point/Point2D";
import eUtils from '../../utils/every-utils'

export default class Shape2D {
    /**
     * @param centre {Point2D=}
     * @param angle {number=0}
     */
    constructor(centre = new Point2D(0, 0), angle = 0) {
        this.centre = centre;
        this.angle = angle;
        this.shapeBeenCheckedList = [];
        this.collidedShapes = [];
    }

    /**
     * @param shape {Shape2D}
     */
    getDistanceFrom(shape) {
        return this.centre['getDistanceFromAnotherPoint'](shape.centre) - (
            this.getAnglePadding(
                this.centre['getDegFromAnotherPoint'](shape.centre)
            ) + shape.getAnglePadding(
                shape.centre['getDegFromAnotherPoint'](this.centre)
            )
        );
    }

    getHornPoints() {
        // overwrite
    }

    /**
     * @param movement {Movement2D}
     */
    setMovement(movement) {
        this.movement = movement;
    }

    moveByTrack(afterMove, isFollowAngle = false) {
        if (!this.movement) {
            return;
        }
        this.movement.move(this.centre);
        if (isFollowAngle) {
            this.angle = this.movement.angle;
        }
        if (eUtils.isFunction(afterMove)) {
            afterMove.call(this, this.movement);
        }
    }

    /**
     * @param angle {number}
     * @returns {number}
     */
    getAnglePadding(angle) {
        // overwrite
        return 0;
    }

    scale() {

    }

    /**
     * @param shapes {Array<Shape2D>}
     */
    doCollisionChecked(shapes) {
        shapes.forEach(shape => {
            if (eUtils.isContainsObject(this.shapeBeenCheckedList, shape) || shape === this) {
                return;
            }
            if (!eUtils.isContainsObject(shape.shapeBeenCheckedList, this)) {
                shape.shapeBeenCheckedList.push(this);
            }
            let distance = this.getDistanceFrom(shape);
            if (distance <= 0 && !this.isCollidedFrom(shape)) {
                this.collidedShapes.push(shape);
                this.checkedCollided.call(this, shape);
            } else if (distance > 0 && this.isCollidedFrom(shape)) {
                this.collidedShapes = this.collidedShapes.filter(s => {
                    return s !== shape;
                })
            }
        });
    }

    /**
     * @param shape {Shape2D}
     */
    getTouchLineFaceAngel(shape) {
        return 0;
    }

    onCollided() {
    }

    /**
     * @param shape {Shape2D}
     */
    checkedCollided(shape) {
        this.onCollided.call(this, this.getTouchLineFaceAngel(shape), shape);
        shape.onCollided.call(this, shape.getTouchLineFaceAngel(this), this);
    }

    isCollidedFrom(shape) {
        return eUtils.isContainsObject(this.collidedShapes, shape);
    }

    /**
     * @param deg {number}
     * @param point {Point2D=}
     */
    rotate(deg, point) {
        if (point && (point instanceof Point2D)) {
            let aimDeg = point['getDegFromAnotherPoint'](this.centre);
            let distance = point['getDistanceFromAnotherPoint'](this.centre);
            aimDeg += deg;
            if (aimDeg <= 0) {
                aimDeg = 360 - Math.abs(this.angle) % 360;
            }
            if (aimDeg > 360) {
                aimDeg %= 360;
            }
            this.centre = point['getOtherPointFromDistanceAndDeg'](distance, aimDeg);
        }
        this.angle += deg;
        if (this.angle <= 0) {
            this.angle = 360 - Math.abs(this.angle) % 360;
        }
        if (this.angle > 360) {
            this.angle %= 360;
        }

    }
}